package org.easystub;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.InvocationHandler;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

import java.lang.reflect.Method;
import java.util.List;

public class CglibProxyFactory {

    private final Objenesis objenesis;

    public CglibProxyFactory() {
        this.objenesis = new ObjenesisStd();
    }

    @SuppressWarnings("unchecked")
    public <T> T createProxy(InvocationHandlerParameters<T> params) {
        final StubInvocationHandler handler = new StubInvocationHandler(params);
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(params.getStubbedClass());
        enhancer.setInterfaces(new Class[]{InvocationHandlerLocator.class});
        enhancer.setCallbackType(InvocationHandler.class);
        Callback callback = new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                return handler.invoke(o, method, objects);
            }
        };

        Class<T> generated = enhancer.createClass();
        Factory proxy = (Factory) objenesis.newInstance(generated);
        proxy.setCallbacks(new Callback[]{callback});
        return (T) proxy;
    }
}
